<?php
/**
 * crcl/base
 *
 * Copyright 2013 CRCL - André Sabosch - info@crcl.de
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * base exceptions with causes and statuscodes
 */

namespace crcl\base;

interface IException
{
  /**
   * Constructor of base exceptions
   *
   * @param string  $sMessage Message
   * @param array|object Causes, optional
   */
  public function __construct($sMessage, $aCauses = array());

  /**
   * Overrides message
   *
   * @param string $sMessage  Message
   */
  public function setMessage($sMessage);

  /**
   * Overrides causes object
   *
   * @param array|object Causes
   */
  public function setCauses($causes);
  
  /**
   * Adds new cause to causes
   * 
   * @chain
   * @param mixed $key
   * @param mixed $value
   */
  public function addCause($key, $value);

  /**
   * Returns causes object of exception
   *
   * @return exception\ICauses
   */
  public function getCauses();
}

class Exception extends \Exception implements IException
{
  const STATUS_DEFAULT = 500;
  const STATUS_404 = 404;

  public function __construct($sMessage = \NULL, $code = 0, $causes = array(),
                              $iStatus = self::STATUS_DEFAULT)
  {
    if (!\is_array($causes))
    {
      $causes = array('cause' => $causes);
    }
    $this->setCauses($causes);
    $this->setStatus($iStatus);

    $sCauses = '(';
    foreach ($causes as $key => $cause)
    {
      if ($sCauses !== '(')
      {
        $sCauses .= ' / ';
      }
      if (\is_array($cause))
      {
       // $cause = '[array]';
        $cause = \var_export($cause, \TRUE);
        $cause = \str_replace("\n", '', $cause);
      }
      $sCauses .= $key . ': ' . (string)$cause;
    }
    $sCauses .= ')';

    if ($sCauses !== '()')
    {
      $sMessage .= ' ' . $sCauses;
    }

    $this->code = $code;

    parent::__construct($sMessage, (int)$code);
  }

  public function getCauses()
  {
    return $this->oCauses;
  }

  public function setCauses($causes)
  {
    if (!($causes instanceof exception\ICauses))
    {
      $causes = exception\Causes::fromArray($causes);
    }
    $this->oCauses = $causes;
  }
  
  public function addCause($key, $value)
  {
    $this->oCauses->add($key, $value);
    return $this;
  } 

  public function setMessage($sMessage)
  {
    $this->message = $sMessage;
  }

  public function setStatus($iStatus)
  {
    $this->iStatus = $iStatus;
  }

  public function getStatus()
  {
    return $this->iStatus;
  }

  /** PRIVATE *************************************************************************************/

  private $oCauses;
  private $iStatus;
  protected $code;
}